package org.jeeasy.generate.generator;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.NamingCase;
import cn.hutool.core.util.StrUtil;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.jeeasy.common.core.annotation.convert.BeanTransfer;
import org.jeeasy.common.core.base.BaseEntity;
import org.jeeasy.common.core.base.convert.BaseConverter;
import org.jeeasy.common.core.base.convert.BaseTransfer;
import org.jeeasy.common.core.enums.BooleanEnum;
import org.jeeasy.common.core.tools.Tools;
import org.jeeasy.generate.domain.GenTableField;
import org.jeeasy.generate.emuns.JavaTypeEnum;
import org.jeeasy.generate.emuns.ValidRuleEnum;
import org.mapstruct.Mapper;

import java.util.ArrayList;
import java.util.List;

@Data
@Slf4j
@EqualsAndHashCode(callSuper = true)
@BeanTransfer(value = FieldContext.Converter.class)
public class FieldContext extends BaseTransfer<GenTableField> {


    private CaseName caseName;
    private String tsType;
    private String hiddenType;
    private String disabledType;
    private boolean ignoreEntity;
    private String javaFieldAnnotation = "";
    private boolean ignoreVo;
    private String fieldSwaggerAnnotation = "";
    private boolean ignoreDto;
    private String fieldValidAnnotation = "";
    private Boolean supperField = false;

    /**
     * 表ID
     */
    private String tableId;

    /**
     * 列名
     */
    private String columnName;

    /**
     * 主键
     */
    private Integer primaryKey;

    /**
     * 字段名
     */
    private String fieldName;

    /**
     * 字段描述
     */
    private String description;

    /**
     * 数据类型
     */
    private String jdbcType;

    /**
     * java类型
     */
    private String javaType;

    /**
     * 字段长度
     */
    private Integer length;

    /**
     * 小数位
     */
    private Integer decimalPlaces;

    /**
     * 允许空值
     */
    private Integer allowNull;

    /**
     * 默认值
     */
    private String defaultValue;

    /* 页面配置 */

    /**
     * 字典
     */
    private String dictCode;

    /**
     * 表单类型
     */
    private String formType;

    /**
     * 页面配置（json）
     */
    private String viewOptionsJson;

    /**
     * 新增显示
     */
    private Integer showAdd;

    /**
     * 修改显示
     */
    private Integer showEdit;

    /**
     * 列表展示
     */
    private Integer showTable;

    /**
     * 搜索展示
     */
    private Integer showSearch;

    /**
     * 修改时禁用
     */
    private Integer disableOnEdit;

    /**
     * 新增时禁用
     */
    private Integer disableOnAdd;

    /**
     * 行内编辑时禁用
     */
    private Integer disableOnTableEdit;

    /* 校验路径 */
    private String fieldPath;

    /**
     * 必填
     */
    private Integer required;

    /**
     * 校验规则
     */
    private String rule;

    /* 外键关联 */

    /**
     * 主表
     */
    private String mainTable;

    /**
     * 主表字段
     */
    private String mainTableField;

    //private static final String[] ignoreFields = {"id", "createBy", "createTime", "updateBy", "updateTime", "delFlag", "sysOrgCode", "serialVersionUID"};

    private String getStringValue(String val) {
        return String.format("\"%s\"", val);
    }

    private static final List<String> ignoreVoFields = List.of("delFlag", "serialVersionUID");
    private static final List<String> ignoreDtoFields = List.of("createBy", "createTime", "updateBy", "updateTime", "delFlag", "version", "serialVersionUID");

    public void putField() {

        this.caseName = new CaseName(this.fieldName);
        this.ignoreEntity = FieldUtils.getField(BaseEntity.class, this.fieldName, true) != null;
        this.ignoreVo = ignoreVoFields.contains(this.fieldName);
        this.ignoreDto = ignoreDtoFields.contains(this.fieldName);

        if (!this.ignoreEntity) {
            toJavaFieldAnnotation();
            toValidAnnotation();
        }
        toSwaggerAnnotation();
        toTsType();
        toHiddenType();
        toDisabledType();

    }

    public void toSwaggerAnnotation() {
        // @Schema(description = "ID")
        //List<String> columnAnnotations = new ArrayList<>(List.of("description = " + getStringValue(this.description)));
        //String annotations = String.join(", ", columnAnnotations);
        this.fieldSwaggerAnnotation = String.format("\n    @Schema(description = %s)", getStringValue(this.description));
        if (StrUtil.isNotBlank(this.dictCode)) {
            fieldSwaggerAnnotation += String.format("\n    @Dict(%s)", getStringValue(this.dictCode));
        }
    }

    public void toValidAnnotation() {
        List<String> columnAnnotations = new ArrayList<>();
        if (!BooleanEnum.yes(this.allowNull)) {
            if (JavaTypeEnum.STRING.is(this.javaType)) {
                columnAnnotations.add(String.format("@NotBlank(message = \"%s不能为空\")", this.description));
            } else {
                columnAnnotations.add(String.format("@NotNull(message = \"%s不能为空\")", this.description));
            }
        }
        if (this.length != null && this.length > 0) {
            columnAnnotations.add(String.format("@Length(max = %s, message = \"%s长度不能超过%s个字符\")", this.length, this.description, this.length));
        }

        if (this.rule != null) {
            columnAnnotations.add(switch (ValidRuleEnum.getByValue(this.rule)) {
                        case MOBILE_PHONE ->
                                "@Pattern(regexp = ValidatorPattern.MOBILE_PHONE, message = ValidatorPattern.MOBILE_PHONE_MSG)";
                        case PHONE -> "@Pattern(regexp = ValidatorPattern.PHONE, message = ValidatorPattern.PHONE_MSG)";
                        case EMAIL -> "@Email(message = ValidatorPattern.EMAIL_MSG)";
                        case ID_CARD -> "@Pattern(regexp = ValidatorPattern.ID_CARD, message = ValidatorPattern.ID_CARD_MSG)";
                        case IP -> "@Pattern(regexp = ValidatorPattern.IP, message = ValidatorPattern.IP_MSG)";
                        case IPV4 -> "@Pattern(regexp = ValidatorPattern.IPV4, message = ValidatorPattern.IPV4_MSG)";
                        case IPV6 -> "@Pattern(regexp = ValidatorPattern.IPV6, message = ValidatorPattern.IPV6_MSG)";
                        case URL -> "@Pattern(regexp = ValidatorPattern.URL, message = ValidatorPattern.URL_MSG)";
                        case BANK_CARD ->
                                "@Pattern(regexp = ValidatorPattern.BANK_CARD, message = ValidatorPattern.BANK_CARD_MSG)";
                        case PASSWORD ->
                                "@Pattern(regexp = ValidatorPattern.PASSWORD, message = ValidatorPattern.PASSWORD_MSG)";
                        case PASSWORD_STRONG ->
                                "@Pattern(regexp = ValidatorPattern.PASSWORD_STRONG, message = ValidatorPattern.PASSWORD_STRONG_MSG)";
                        default ->
                                String.format("@Pattern(regexp = \"%s\", message = \"%s格式不正确\")", this.rule, this.description);
                    }
            );
        }
        this.fieldValidAnnotation = String.join("\n    ", columnAnnotations);
    }

    private void toJavaFieldAnnotation() {
        this.javaFieldAnnotation = "";
        if ("sysOrgCode".equals(this.getFieldName())) {
            this.javaFieldAnnotation += "\n    @InsertUpdateFillData(SysOrgCodeAutoFillHandler.class)";
        }
        List<String> columnAnnotations = new ArrayList<>(List.of("comment = " + getStringValue(this.description)));
        if (!this.getColumnName().equals(NamingCase.toUnderlineCase(this.getFieldName()))) {
            columnAnnotations.add("value = " + getStringValue(this.getColumnName()));
        }
        if (!BooleanEnum.yes(this.getAllowNull())) {
            columnAnnotations.add("notNull = " + "true");
        }
        if (this.getLength() != null && this.getLength() > 0) {
            columnAnnotations.add("length = " + this.getLength());
        }
        if (this.getDecimalPlaces() != null && this.getDecimalPlaces() > 0) {
            columnAnnotations.add("decimalLength = " + this.getDecimalPlaces());
        }
        if (this.getJdbcType() != null) {
            columnAnnotations.add("type = " + String.format("MysqlTypeConstant.%s", this.getJdbcType().toUpperCase()));
        }
        if (StrUtil.isNotBlank(this.getDefaultValue())) {
            columnAnnotations.add("defaultValue = " + getStringValue(this.getDefaultValue()));
        }
        String annotations = String.join(", ", columnAnnotations);
        this.javaFieldAnnotation += String.format("\n    @Column(%s)", annotations);
        //log.debug(this.javaFieldAnnotation);
    }

    private void toDisabledType() {
        List<String> disabledTypes = new ArrayList<>();
        int disableOnTableEdit = Tools.isEmpty(this.getDisableOnTableEdit()) ? 0 : this.getDisableOnTableEdit();
        int disableOnAdd = Tools.isEmpty(this.getDisableOnAdd()) ? 0 : this.getDisableOnAdd();
        int disableOnEdit = Tools.isEmpty(this.getDisableOnEdit()) ? 0 : this.getDisableOnEdit();
        int show = disableOnTableEdit + disableOnAdd + disableOnEdit;
        if (show == 0) {
            disabledTypes.add("false");
        } else {
            if (disableOnTableEdit == 1) {
                disabledTypes.add("'editTable'");
            }
            if (disableOnAdd + disableOnEdit == 2) {
                disabledTypes.add("'form'");
            } else {
                if (disableOnAdd == 1) {
                    disabledTypes.add("'add'");
                }
                if (disableOnEdit == 1) {
                    disabledTypes.add("'edit'");
                }
            }
        }
        this.disabledType = CollectionUtil.join(disabledTypes, ", ");
    }

    /**
     * 将控件类型设置为隐藏类型
     */
    private void toHiddenType() {
        // 创建一个存储隐藏类型的列表
        List<String> hiddenTypes = new ArrayList<>();

        // 获取showTable、showSearch、showAdd、showEdit的值，如果为空则设置为0
        int showTable = Tools.isEmpty(this.getShowTable()) ? 0 : this.getShowTable();
        int showSearch = Tools.isEmpty(this.getShowSearch()) ? 0 : this.getShowSearch();
        int showAdd = Tools.isEmpty(this.getShowAdd()) ? 0 : this.getShowAdd();
        int showEdit = Tools.isEmpty(this.getShowEdit()) ? 0 : this.getShowEdit();

        // 打印日志信息
        //log.debug("{} ---> showTable:{}, showSearch:{}, showAdd:{}, showEdit {}", this.caseName.getCamel(), showTable, showSearch, showAdd, showEdit);

        // 计算show的值
        int show = showTable + showSearch + showAdd + showEdit;

        // 根据show的值设置隐藏类型
        if (show == 0) {
            hiddenTypes.add("true");
        } else if (show == 4) {
            hiddenTypes.add("false");
        } else {
            if (showTable == 0) {
                hiddenTypes.add("'list'");
                hiddenTypes.add("'view'");
            }
            if (showSearch == 0) {
                hiddenTypes.add("'query'");
            }
            if (showAdd + showEdit == 0) {
                hiddenTypes.add("'form'");
            } else {
                if (showAdd == 0) {
                    hiddenTypes.add("'add'");
                }
                if (showEdit == 0) {
                    hiddenTypes.add("'edit'");
                }
            }
        }

        // 将隐藏类型列表转换为字符串，并设置join为该字符串
        //log.debug("hiddenType ---> {}", join);
        this.hiddenType = CollectionUtil.join(hiddenTypes, ", ");
    }


    private void toTsType() {
        String javaType = getJavaType();
        if (Tools.isEmpty(javaType)) {
            this.tsType = "string";
            return;
        }
        JavaTypeEnum javaTypeEnum = JavaTypeEnum.getByValue(javaType);
        this.tsType = javaTypeEnum.getTsType();
        //this.tsType = switch (javaTypeEnum) {
        //    case INTEGER, LONG, DOUBLE, FLOAT, BIG_INTEGER, BIG_DECIMAL, BYTE, DATE, TIME, DATETIME -> "number";
        //    case BOOLEAN -> "boolean";
        //    default -> "string";
        //};
    }


    @Mapper
    public interface Converter extends BaseConverter<GenTableField, FieldContext> {
    }
}
